using System;
using System.Xml.Serialization;
using Core.Graphics;
using Microsoft.Xna.Framework;
using Core.Graphics.Layers;

namespace Core.Mapping
{
    [Serializable()]
    [XmlRoot("TileMap")]
    public class Map : TilePainting
    {
        public static int MapHeight = 128;
        public static int MapWidth = 128;

        #region Basic Map Properties
        /// <summary>Map Upper-Left X Coordinate</summary>
        [XmlAttribute("WorldX")]
        public int WorldX { get; set;  }
        /// <summary>Map Upper-Left Y Coordinate</summary>
        [XmlAttribute("WorldY")]
        public int WorldY { get; set; }

        [XmlElement("LandTiles")]
        public LandLayer LandLayer { get; set; }

        [XmlElement("CollisionLayer")]
        public CollisionLayer Collision { get; set; }

        //Base layer
        [XmlElement("BaseLayer")]
        public MapLayer BaseLayer { get; set; }

        //Terrain Layers
        [XmlElement("TerrainLayer")]
        public MapLayer TerrainLayer { get; set; }

        [XmlElement("TerrainDetailLayer")]
        public MapLayer TerrainDetailLayer { get; set; }

        [XmlElement("TerrainSuperDetailLayer")]
        public MapLayer TerrainSuperDetailLayer { get; set; }
        #endregion

        public Map()
        {
            //Xml Serialization
        }

        public static Map NewEmptyMap(int worldx, int worldy)
        {
            Map tm = new Map();

            tm.WorldX = worldx;
            tm.WorldY = worldy;
            tm.Name = "Empty Map";

            tm.LandLayer = new LandLayer(MapWidth, MapHeight);
            tm.Collision = new CollisionLayer(MapWidth, MapHeight);
            tm.Layers = new LayerCollection();
            //---Create Layers---//
            //Create Base Layer
            tm.BaseLayer = new MapLayer(MapLayerTypes.Base);
            //Crate all Terrain Level layers
            tm.TerrainLayer = new MapLayer(MapLayerTypes.Terrain);
            tm.TerrainDetailLayer = new MapLayer(MapLayerTypes.TerrainDetail);
            tm.TerrainSuperDetailLayer = new MapLayer(MapLayerTypes.TerrainSuperDetail);


            return tm;
        }

        public MapLayer GetLayerByLayerType(MapLayerTypes type)
        {
            switch (type)
            {
                //Base
                case MapLayerTypes.Base:
                    return BaseLayer;

                //Terrain Types
                case MapLayerTypes.Terrain:
                    return TerrainLayer;

                case MapLayerTypes.TerrainDetail:
                    return TerrainDetailLayer;

                case MapLayerTypes.TerrainSuperDetail:
                    return TerrainSuperDetailLayer;

                default:
                    return new MapLayer();

            }
        }

        public LayerCollection GetLayersByBaseType(MapLayerBaseTypes baseType)
        {
            LayerCollection tmlc = new LayerCollection();

            switch (baseType)
            {
                case MapLayerBaseTypes.Base:
                    tmlc.Add(BaseLayer);
                    break;

                case MapLayerBaseTypes.Terrain:
                    tmlc.Add(TerrainLayer);
                    tmlc.Add(TerrainDetailLayer);
                    tmlc.Add(TerrainSuperDetailLayer);
                    break;
                case MapLayerBaseTypes.Collection:
                    tmlc = Layers;
                    break;
            }

            return tmlc;
        }

        public new bool IsTileWalkable(int x, int y)
        {
            if (x < 0 || y < 0)
                return false;

            //Adjust x and y for from world coordinates to map coordinates
            x -= WorldX;
            y -= WorldY;

            //TODO: Rebuild Collision System using new GameObject System. For now we will return true for all instances
            return true;

            //Tile mt = (Tile)_GroundCollisionLayer.Tiles[(y * _MapWidth) + x];

            //if (mt.SpriteID.ID == -1)
            //{
            //    return true;
            //}
            //else
            //{
            //    return false;
            //}
        }

        public bool IsCoordinateInMap(Point worldC)
        {
            if (worldC.X >= WorldX && worldC.Y >= WorldY &&
                worldC.X < WorldX + Map.MapWidth && worldC.Y < WorldY + Map.MapHeight)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public Tile GetTileAtLocation(Point worldC, MapLayerTypes layer)
        {
            MapLayer tml = GetLayerByLayerType(layer);

            Point local = GetMapCoordinatesFromWorldCoordinates(worldC);

            return tml.GetTileAtLocation(local.X, local.Y);
        }

        public void SetTileAtLocation(Point worldC, MapLayerTypes layer, Tile setTile)
        {
            MapLayer tml = GetLayerByLayerType(layer);

            tml.SetTileAtLocation(setTile, worldC.X, worldC.Y);
        }

        public Point GetMapCoordinatesFromWorldCoordinates(Point worldC)
        {
            return new Point(worldC.X - WorldX, worldC.Y - WorldY);
        }
    }
}